package com.ilxqx.fierce.core;

import cn.hutool.core.bean.BeanPath;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import com.ilxqx.fierce.entity.FierceEntity;
import com.ilxqx.fierce.exception.FierceRequestException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.support.AopUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.core.ResolvableType;

import java.util.List;
import java.util.Map;

/**
 * 请求处理器
 *
 * @author Venus
 * @since 1.0.0
 */
@Slf4j
public final class RequestHandlerDelegate {

    private static final String MAPPER_SUFFIX = "Mapper";
    private static final String SERVICE_SUFFIX = "Service";
    private static List<CommonActionHandler> commonActionHandlers;
    private static final BeanPath MAPPER_CLASS_PATH = BeanPath.create("h.mapperInterface");

    /**
     * 处理请求
     *
     * @param request 请求对象
     * @param applicationContext 应用上下文
     * @return 响应对象
     */
    public static FierceResponse handleRequest(FierceRequest request, ApplicationContext applicationContext) {
        FierceRequestContext context = parseRequestContext(request, applicationContext);

        retrieveCommonHandlers(applicationContext);

        FierceRequestContextHolder.set(context);
        try {
            // 处理通用请求
            return doHandleRequest(request);
        } catch (Throwable throwable) {
            log.error("请求遭遇异常: {}", throwable.getMessage(), throwable);
            return FierceResponse.fail(throwable instanceof NullPointerException ? "空指针异常！" : throwable.getMessage());
        } finally {
            FierceRequestContextHolder.clear();
        }
    }

    /**
     * 真正处理请求逻辑
     *
     * @param request 请求对象
     * @return 响应对象
     */
    private static FierceResponse doHandleRequest(FierceRequest request) {
        for (CommonActionHandler commonActionHandler : commonActionHandlers) {
            if (commonActionHandler.supports(request.getAction())) {
                return commonActionHandler.handle(request.getAction(), request.getData());
            }
        }

        return ActionHandlerDelegate.handleAction(request);
    }

    /**
     * 获取通用请求处理器
     *
     * @param applicationContext 上下文对象
     */
    private static void retrieveCommonHandlers(ApplicationContext applicationContext) {
        if (commonActionHandlers == null) {
            Map<String, CommonActionHandler> beansOfType = applicationContext.getBeansOfType(CommonActionHandler.class);
            commonActionHandlers = Lists.newArrayList(beansOfType.values());
        }
    }

    /**
     * 解析请求上下文
     *
     * @param request 请求对象
     * @param applicationContext 应用上下文
     * @return 请求上下文
     */
    @SuppressWarnings("unchecked")
    private static FierceRequestContext parseRequestContext(FierceRequest request, ApplicationContext applicationContext) {
        String service = StrUtil.toCamelCase(request.getService());
        String mapperName = service + MAPPER_SUFFIX;
        FierceRequestContext context = new FierceRequestContext();

        if (applicationContext.containsBean(mapperName)) {
            Object mapperBean = applicationContext.getBean(mapperName);
            Class<?> mapperClass = (Class<?>) MAPPER_CLASS_PATH.get(mapperBean);
            context.setMapper(mapperBean);
            context.setMapperClass(mapperClass);

            if (FierceMapper.class.isAssignableFrom(mapperClass)) {
                // 说明是FierceMapper
                ResolvableType[] interfaces = ResolvableType.forClass(mapperClass).getInterfaces();
                if (interfaces.length == 0) {
                    throw new FierceRequestException("解析Mapper实体类出现未知异常！");
                }
                Class<? extends FierceEntity> entityClass = (Class<? extends FierceEntity>) interfaces[0].resolveGeneric(0);
                context.setEntityClass(entityClass);
            }
        }

        String serviceName = service + SERVICE_SUFFIX;
        if (!applicationContext.containsBean(serviceName)) {
            throw new FierceRequestException("Service[" + serviceName + "]不存在！");
        }

        Object serviceBean = applicationContext.getBean(serviceName);
        context.setService(serviceBean);
        context.setServiceClass(AopUtils.getTargetClass(serviceBean));

        return context;
    }
}
